#include "decoder.h"
#include <algorithm>

// 接收‘0’或‘1’，返回0或1
inline unsigned char2int(unsigned u)
{
    return u & ~0b110000;
}

void Decoding(FILE *fp_decode, const string &dest)
{
    FILE *fp_encode = fopen(dest.begin().base(), "w");
    string Decoding_List[ASCII_MAXSIZE];
    byte_t length = 0, cur_length;
    short encode = 0;
    string tmp;

    for (auto &item: Decoding_List) {
        cur_length = 0;
        virtualFread(&length, sizeof(byte_t), 1, fp_decode);
        virtualFread(&encode, sizeof(short), 1, fp_decode);
        tmp = "";
        while (encode) {
            tmp += (char) ('0' + (encode & 1));
            encode >>= 1;
            cur_length++;
        }
        while (cur_length < length)
            tmp += "0", cur_length++;
        reverse(tmp.begin(), tmp.end());
        item = tmp;
    }

    Node *root = new Node;
    for (int i = 0; i < ASCII_MAXSIZE; i++) {
        if (Decoding_List[i].empty())
            continue;
        Node *p = root;
        for (auto e: Decoding_List[i]) {
            bool f = e - '0';
            if (!f) {
                if (!p->lc)
                    p->lc = new Node;
                p = p->lc;
            } else {
                if (!p->rc)
                    p->rc = new Node;
                p = p->rc;
            }
        }
        p->data = i;
    }

    byte_t buffer[BLOCK_SIZE] = {0};
    size_t read_count;
    Node *p = root;
    while ((read_count = virtualFread(buffer, 1, BLOCK_SIZE, fp_decode)) != 0) {
        for (int i = 0; i < read_count; i++) {
            bool f = buffer[i] - '0';
            p = f ? p->rc : p->lc;
            if (!p->lc && !p->rc) {
                fwrite(&p->data, sizeof(byte_t), 1, fp_encode);
                p = root;
            }
        }
    }
}

byte_t readByte(FILE *fp)
{
    byte_t bits[BITS_PER_BYTE] = {0};
    size_t readCount = fread(bits, sizeof(byte_t), BITS_PER_BYTE, fp);

    for (size_t i = readCount; i < BITS_PER_BYTE; ++i)
        bits[i] = '0';

    byte_t byte = 0;
    for (byte_t bit: bits) {
        bit = char2int(bit); // '1' to 1, '0' to 0
        byte <<= 1;
        byte |= bit;
    }
    return byte;
}

size_t virtualFread(void *buff, size_t elementSize, size_t count, FILE *fp)
{
    auto pbyte = (byte_t *) buff;
    size_t elemCount = 0;

    for (size_t i = 0; i < count && !feof(fp); ++i) {
        for (size_t j = 0; j < elementSize; ++j)
            *pbyte++ = readByte(fp);

        ++elemCount;
    }
    return elemCount;
}